﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using NoMvvm;
using NoMvvm.MEF;
using NoMvvm.Wpf;
using Templates.Models;

namespace Templates.ViewModels
{
    [ViewModel("Main")]
    public sealed class MainViewModel : ViewModel
    {
        private readonly IDialogService _dialogService;
        private readonly IMessageBoxService _mbService;
        private readonly TemplateFormatter _formatter;
        private readonly Serializer _serializer;

        [ImportingConstructor]
        public MainViewModel(
            IDialogService dialogService,
            IMessageBoxService mbService,
            TemplateFormatter formatter,
            Serializer serializer)
        {
            _dialogService = dialogService;
            _mbService = mbService;
            _formatter = formatter;
            _serializer = serializer;

            This.StartCharacter = "[";
            This.EndCharacter = "]";
            This.IgnoreCase = true;
            This.Variables = new ObservableCollection<dynamic>();
        }

        public void About()
        {
            _mbService.Show(View, "Templates was created by Jonathan Peppers and is free to use and modify by anyone.", "About Templates");
        }

        public void Close()
        {
            View.Close();
        }

        public void AddVariable()
        {
            This.Variables.Add(NewVariable(new Variable()));
        }

        public void ImportTemplate()
        {
            string path;
            if (_dialogService.OpenFile(out path))
            {
                Template template = ThisToTemplate();
                template.Body = File.ReadAllText(path);
                template = _formatter.Read(template);
                This.Variables = template.Variables;
            }
        }

        public void OpenTemplate()
        {
            string path;
            if (_dialogService.OpenFile(out path))
            {
                Template template = _serializer.Open(path);
                TemplateToThis(template);
            }
        }

        public void OpenFile()
        {
            string path;
            if (_dialogService.OpenFile(out path))
            {
                This.Body = File.ReadAllText(path);
            }
        }

        public void SaveTemplate()
        {
            string path;
            if (_dialogService.SaveFile(out path))
            {
                _serializer.Save(path, ThisToTemplate());
            }
        }

        public void SaveFile()
        {
            string path;
            if (_dialogService.SaveFile(out path))
            {
                string text = _formatter.Write(ThisToTemplate());

                File.WriteAllText(path, text);
            }
        }

        public override void Rescue(Exception exc)
        {
            _mbService.Show(View, exc.Message, "Error");
        }

        private Template ThisToTemplate()
        {
            return new Template
            {
                IgnoreCase = This.IgnoreCase ?? true,
                EndCharacter = This.EndCharacter,
                StartCharacter = This.StartCharacter,
                Variables = ((IEnumerable<dynamic>)This.Variables)
                    .Select(v => new Variable { Name = v.Name, Value = v.Value }).ToList(),
                Body = This.Body,
            };
        }

        private void TemplateToThis(Template template)
        {
            This.Body = template.Body;
            This.IgnoreCase = template.IgnoreCase;
            This.EndCharacter = template.EndCharacter;
            This.StartCharacter = template.StartCharacter;
            This.Variables = new ObservableCollection<dynamic>(template.Variables.Select(NewVariable));
        }

        private dynamic NewVariable(Variable variable)
        {
            dynamic viewModel = new ViewModel();
            viewModel.Name = variable.Name;
            viewModel.Value = variable.Value;
            viewModel.Delete = (Action)delegate { This.Variables.Remove(viewModel); };
            return viewModel;
        }
    }
}
